// **************************************************************
// COPYRIGHT(c)2010, xidian University
// All rights reserved.
//
// IP LIB INDEX  :  HiNOC
// IP Name       :  HiNOC
// File name     :  write_ctrl.v
// Module name   :  CPT_WRITE_CTRL
// Full name     :  CPTURE WRITE CONTRL
//
// Author        :  Pan Weitao
// Email         :  panweitao@163.com
// Data          :  2010???10???8???9:54:26
// Version       :  V 1.0
//
// Abstract      :
// Called by     :  CPT_CTRL
//
// Modification history
// ------------------------------------------------------------------------------------------------------
// //
// $Log$
//
// *********************************************************************

`include    "top_define.v"
`define     MAX_NUM 512 
// *****************************
//  DEFINE MODULE PORT  //
// ******************************
module CPT_WRITE_CTRL_NEW(
             //input
             clk                   ,
             rst_n                 ,
             cpt_data_val          ,
             cpt_data              ,

             cpt_en                ,
             cpt_frame_len         ,     

             hm_id                 ,	 
             //output

             dpram_data_i          ,
             dpram_addr			   ,
			 dpram_wren			   ,
								   
			 cpt_info_fifo_data	   ,
			 cpt_info_fifo_wren    ,
			  
             rd_end                ,
             cpt_rd_frame_len      ,
             cpt_busy               
           );

parameter CPT_WIDTH =10; //八个最长EMAC
// ******************************
// DEFINE INPUT
// ******************************         
input          clk                    ;
input          rst_n                  ;      
input          cpt_data_val           ;
input  [255:0] cpt_data               ;


input          cpt_en                 ;
input  [10:0]  cpt_frame_len          ;//from outside

input  [7:0]   hm_id                  ;

// ******************************
// DEFINE OUTPUT  //
// ******************************      

output reg [255:0]         dpram_data_i;
output reg [CPT_WIDTH-1:0] dpram_addr  ;
output reg 		   		   dpram_wren  ;

output reg [31:0]  cpt_info_fifo_data  ;
output reg 		   cpt_info_fifo_wren  ;

input          rd_end                  ;
input [10:0]   cpt_rd_frame_len        ;
output         cpt_busy 			   ;

// ******************************
// OUTPUT ATRRIBUTE  //
// ******************************                                   
//REGS

// PARAMETERS
parameter IDLE				= 5'b00001;
parameter WRITE_HEADER_INFO = 5'b00010;
parameter WAIT              = 5'b00100;
parameter WRITE_DATA 		= 5'b01000;
parameter WRITE_CPU_FIFO	= 5'b10000;
(*mark_debug = "true"*) reg [4:0] cstate;
(*mark_debug = "true"*) reg [4:0] nstate;
//WIRES


// ******************************
// INTERNAL ATRRIBUTE  //
// ******************************                                   
//REGS
// reg  [1:0]  current_state  ;
// reg  [1:0]  next_state     ;

reg         wr_val;

reg         wr_val_ff1;
wire        wr_val_neg;
reg         cpt_en_ff1;
wire        cpt_en_pos;  
reg  [10:0] cpt_frame_len_ff1;

reg  [15:0] 	start_addr;
//reg  [15:0] 	end_addr;
reg  [CPT_WIDTH:0] free_size;

reg  [10:0] frame_len4byte;

reg  [8:0] cpt_rd_frame_len_4byte;

//MAIN CODE
assign cpt_busy = (cstate!=IDLE);

//状态机第一段
always @ (posedge clk or negedge rst_n) begin
	if(!rst_n)
		cstate <= IDLE;
    else
		cstate <= nstate;
end		

//状态机第二段		
always@(*) begin
	case(cstate)
		IDLE:
			if(cpt_en_pos)
				nstate = WAIT;
			else
				nstate = IDLE;
		WAIT:
			if(free_size < {2'b0,frame_len4byte})
				nstate = IDLE;
			else if (cpt_data_val)
				nstate = WRITE_DATA ;
			else 
				nstate = WAIT ;
               /*nstate = WRITE_HEADER_INFO;
        		WRITE_HEADER_INFO:
            if(cpt_data_val)
                nstate = WRITE_DATA;
            else 
                nstate = WRITE_HEADER_INFO;*/
		WRITE_DATA:
			if(cpt_data_val)
				nstate = WRITE_DATA;
			else 
				nstate = WRITE_CPU_FIFO;
		WRITE_CPU_FIFO:
			nstate = IDLE;
		default:
			nstate = IDLE;
		endcase
end

//用于信息FIFO，记录改帧的起始地址
always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n)
		start_addr <= 16'd0;
	else if(/*nstate == WRITE_HEADER_INFO && */cstate == WAIT && nstate == WRITE_DATA)
		start_addr <= {{(16-CPT_WIDTH){1'b0}} ,dpram_addr};
end


//理论上这个帧要占用的256bit
always @ (posedge clk or negedge rst_n)
begin 
	if(!rst_n)
		frame_len4byte <= 11'd0;
	else if(cpt_en_pos==1'b1) begin
        if({cpt_frame_len[4:0]} != 5'b0) 
            frame_len4byte <= cpt_frame_len[10:5] + 6'd1;
		else 
            frame_len4byte <= cpt_frame_len[10:5] + 6'd0;   
	end
end

//从捕获ram中取出的emac帧占用256bit的个数 
always@(*)
begin
    if({cpt_rd_frame_len[4:0]} != 5'b0) 
		cpt_rd_frame_len_4byte <= cpt_rd_frame_len[10:5] + 6'd1 ;
    else 
		cpt_rd_frame_len_4byte <= cpt_rd_frame_len[10:5] ;   
end


always @ (posedge clk or negedge rst_n)
begin
  if(!rst_n)
    cpt_frame_len_ff1 <= 11'd0;
  else if(cpt_en_pos)
    cpt_frame_len_ff1 <= cpt_frame_len;
end


//存储空间的余量用来判断要捕获的emac帧是否能进入ram 1522*8 = 12176
always @ (posedge clk or negedge rst_n)
begin
	if(!rst_n)
		free_size <= `MAX_NUM ;  /*1'b1,{(CPT_WIDTH){1'b0}}};*/ //初始化可以空间大小
    else 
        case({wr_val_neg,rd_end}) //数据从分组处理搬移完，数据从捕获ram取出完
            2'b10:free_size <= free_size-frame_len4byte;
            2'b01:free_size <= free_size+cpt_rd_frame_len_4byte;
            2'b11:free_size <= free_size+cpt_rd_frame_len_4byte-frame_len4byte;
            default:free_size<= free_size;
        endcase
end

always @ (posedge clk or negedge rst_n)
if(!rst_n)
	dpram_addr <=12'd0;
else if(dpram_wren)
	dpram_addr <= dpram_addr +12'd1;


always @ (posedge clk or negedge rst_n)
if(!rst_n)
	dpram_wren 	<= 1'b0;
else if(nstate == WRITE_DATA /*|| (cstate== WAIT && nstate == WRITE_HEADER_INFO)*/)
	dpram_wren  <= 1'b1;
    else 
	dpram_wren 	<= 1'b0;

always @ (posedge clk or negedge rst_n)
if(!rst_n)
	dpram_data_i <= 256'b0;
else if(nstate == WRITE_DATA && cpt_data_val)
	dpram_data_i <= cpt_data;
else 
	dpram_data_i <= 256'b0;
		

always @ (posedge clk or negedge rst_n)
if(!rst_n)
	cpt_info_fifo_wren <= 1'b0;
else if(nstate == WRITE_CPU_FIFO)
	cpt_info_fifo_wren <= 1'b1;
    else 
	cpt_info_fifo_wren <= 1'b0;

always @ (posedge clk or negedge rst_n)
if(!rst_n)
	cpt_info_fifo_data <= 32'b0;
else if(nstate == WRITE_CPU_FIFO)
	cpt_info_fifo_data <= {5'b0,cpt_frame_len_ff1,start_addr};    //[26:16][15:0];
    else 
	cpt_info_fifo_data <= 32'b0;

// -------------------------------CRC---------------------------------------------------

always @ (posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
        wr_val <=  1'b0;
	else if(/*nstate==WRITE_HEADER_INFO*/ nstate == WRITE_DATA && cstate == WAIT )
        wr_val <= 1'b1;
    else if((wr_val==1'b1) && (nstate == WRITE_CPU_FIFO|| nstate == IDLE))
        wr_val <= 1'b0;
	else 
		wr_val <= wr_val;
end


always @ (posedge clk or negedge rst_n)
begin
    if(rst_n==1'b0)
	    begin
            wr_val_ff1 <=  1'b0;
			cpt_en_ff1 <=  1'b0;
        end
    else
	    begin
            wr_val_ff1 <= wr_val ;		
			cpt_en_ff1 <= cpt_en ;
        end		
end

assign wr_val_neg = ~wr_val & wr_val_ff1;
assign cpt_en_pos = cpt_en & (~cpt_en_ff1);

endmodule
